#include "Rectangle.h"
#include "Particle.h"
#include "Window.h"
#include "Simulation.h"
#include <iostream>
#include <conio.h>
#include <stdio.h>
#include <time.h>
using namespace std;

#ifdef _WIN32
#undef main
#endif

//Drawmode is currently only implemented for regular polygons. Turning drawmode off is required for obtaining data.
//Data is saved in a .csv file. To change the region of interest, change hardcode in the main.cpp and recompile (TODO: switch to command line arguments for region selection)

const bool DRAWMODE = false;
//double argv[5]={0,3,.5,.0035,100000};

static void show_usage(std::string name)
{
	std::cerr << "Usage: " << name << " <-D> <sides> <stepfraction> || " << name << " <sides> <stepfraction> <runs>" << std::endl
		 << "Simulate a particle undergoing Brownian Motion." << std::endl
		 << std::endl
		 << "Options:" << std::endl
		 << "\t<sides>\tThe number of sides of the regular polygon used"<< std::endl
		 << "\t<stepfraction>\tThe fraction of the distance from the center of the polygon to the circumradius for one step" << std::endl
		 << "\t<runs>\tThe number of runs to record in a data file."<< std::endl
		 << "\t-D\tRun in drawmode instead of simulation mode."<< std::endl
		 << std::endl
		 << "The default is to run in simulation mode, which requires the 'sides', 'stepfraction', and 'runs' parameters to be used." << std::endl
		 << "In drawmode, only one run is performed. The 'runs' paramter is not used." << std::endl;
}

void showarguments(int argc, char** argv) //Test function
{
	ofstream ofs("arguments");
	assert(ofs);
	for(int i=0; i< argc; i++)
	{
		ofs << argv[i] << " ";
	}
}

int main(int argc, char** argv)
{
	//First, check the number of parameters
    if(argc < 3) {
        //Less than 4 parameters used. Tell the user how to run the program
        show_usage(argv[0]);
		if(argc==2)
		{
			std::cerr << argv[1];
		}
        return 1;
    }
	clock_t time_i;
	//clock_t time_f; //To get runtime
	time_i = clock();
	if(DRAWMODE)
	{
			//Initialize an SDL window
			try
			{
				Window::Init("Brownian Motion");
			}
			catch (const std::runtime_error &e)
			{
				std::cout << e.what() << std::endl;
				Window::Quit();
				return -1;
			}

			//Set up the brownian motion
			srand((unsigned int)time(NULL));
			Particle brownMoose;
			RegPolygon polygon(atoi(argv[1]));
	
			//Draw the polygon
			Window::Clear(SDL_White);
			Window::DrawRegularPolygon(polygon.sides);
			Window::Present();
	

			//Create the event queue
			bool running = true;
			SDL_Event event;
			while(running){		
				// Check for messages
				while (SDL_PollEvent(&event)){
					switch(event.type){
					case SDL_KEYDOWN:
						switch(event.key.keysym.sym)
						{
						case SDLK_q:
							running = false;
							break;
						}
						break;
					case SDL_KEYUP:
						break;
					case SDL_MOUSEMOTION:
						break;
					case SDL_QUIT:
						running = false;
						break;
					}
				}
				while(polygon.pointInside(brownMoose.position))
				{
					brownMoose.randomMove(atof(argv[2])*polygon.circumradius);
					Window::DrawDot(SCREEN_WIDTH/2+static_cast<int>((SCREEN_WIDTH/2)*brownMoose.position[0]*drawZone),SCREEN_HEIGHT/2+static_cast<int>((SCREEN_HEIGHT/2)*brownMoose.position[1]*drawZone));
					Window::Present();
				}
			}
			//Clean up
			Window::Quit();
			return 0;
		}
		else //No drawmode, used for collecting data
		{
			//Set up the brownian motion
			srand((unsigned int)time(NULL));
			//Region* poly = new RegPolygon(atoi(argv[1]));
			Region* poly = new Rectangle(atof(argv[1]));
			Simulation sim = Simulation(poly,atof(argv[2]));
			int runs = atoi(argv[3]);
			int *data = new int[runs];

			//Enact the Brownian motion
			for(int i=0; i<runs;i++)
			{
				data[i] = sim.run();
			}
			/*time_f = clock();
			float runtime = (float)time_f - (float)time_i;*/
			//Save data to an output file
			sim.save_data_to_csv_file(data,runs);
			//sim.save_data_to_csv_file(data,runs, runtime);
			delete data;
			return 0;
		}
}
